package com.sunshine.schedulegrid.view

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.view.Gravity
import android.widget.Button
import android.widget.LinearLayout
import android.widget.ScrollView
import androidx.constraintlayout.widget.ConstraintLayout
import com.sunshine.schedulegrid.bean.CourseBean
import com.sunshine.schedulegrid.config.ScheduleConfig
import com.sunshine.schedulegrid.utils.ColorUtils
import com.sunshine.schedulegrid.utils.CourseList
import com.sunshine.schedulegrid.utils.DateUtils
import java.lang.StringBuilder
import java.util.*
import kotlin.collections.HashMap

/**
 * @author sunshine
 * @date 2020/8/29
 * @param sc 日程格子配置对象
 * @param thisDateLong 这周的日期Long值
 * @see ColorUtils
 * @see DateUtils
 * @see CourseList
 * @see ScheduleConfig
 * 日程内容布局，用于显示格子
 */
internal class MainView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    sc: ScheduleConfig,
    cl: CourseList?=null,
    thisDateLong: Long = Calendar.getInstance().timeInMillis,
    cu: ColorUtils
) : ScrollView(context, attrs, defStyleAttr) {

    //日程实体列表
    private var courseList = cl

    //日程配置对象
    private var scheduleConfig = sc

    /**
     * 日程显示根布局
     * 该根布局是横向线性布局
     * 线性布局中添加约束布局
     * 这样可以保证平分屏幕
     * 且上下可重叠
     */
    private val root = LinearLayout(context)

    /**
     * 日程布局表，从时间栏到周末添加
     * 使用Map可以保证在不显示当天的情况下不占用空间
     */
    private val scheduleLayouts = HashMap<Int, ConstraintLayout>()

    //这个view为第几周
    private val thisWeek = DateUtils.getThisWeek(thisDateLong)

    //颜色池对象
    private val colorUtils = cu

    init{
        //填充到全屏
        isFillViewport = true

        addView(root)

        addScheduleLayout()
        addTime()
        addSchedule()
    }

    //添加日程布局到根布局
    private fun addScheduleLayout() {
        //0代表时间栏
        scheduleLayouts[0] = ConstraintLayout(context)
        val dateParams = LinearLayout.LayoutParams(scheduleConfig.timeWidth(), LinearLayout.LayoutParams.MATCH_PARENT)
        root.addView(scheduleLayouts[0], dateParams)

        val scheduleParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)

        for (i in 0..6){
            //如果显示该天，则加入到表中
            if (scheduleConfig.showDayOfWeek()[i]){
                //i+1是让周一到周“七”对应上数字
                scheduleLayouts[i+1] = ConstraintLayout(context)
                //添加到根线性布局
                root.addView(scheduleLayouts[i+1], scheduleParams)
            }
        }
    }

    //添加左边时间栏布局
    @SuppressLint("SetTextI18n")
    private fun addTime(){
        //课程模式时间栏
        if (scheduleConfig.scheduleDisplayMode() == ScheduleConfig.LESSON_MODE) {
            //lessonMaxCount包括了午休和晚休
            for (n in 1..scheduleConfig.lessonMaxCount()){
                val timeButton = Button(context)
                timeButton.apply {
                    //背景为透明
                    setBackgroundColor(Color.TRANSPARENT)

                    //区分是否显示
                    text = if (scheduleConfig.showRest()) {
                        when(n){
                            in 1..scheduleConfig.noonRest() -> "$n"
                            scheduleConfig.noonRest() + 1 -> "午休"
                            in scheduleConfig.noonRest() + 2..scheduleConfig.nightRest() + 1 -> "${n-1}"
                            scheduleConfig.nightRest() + 2 -> "晚休"
                            in scheduleConfig.nightRest() + 3..scheduleConfig.lessonMaxCount() -> "${n-2}"
                            else -> ""
                        }
                    } else {
                        "$n"
                    }

                }

                //高度需要计算
                val params = ConstraintLayout.LayoutParams(
                    ConstraintLayout.LayoutParams.MATCH_PARENT,
                    calculateLessonHeight(mode = scheduleConfig.scheduleDisplayMode())
                )

                //固定不动为0
                params.topToTop = 0
                params.leftToLeft = 0

                /**
                 * 主要对应从“第几节”显示
                 * 第n节开始的数值：(n-1) * 一节高度 + n * 每节间隔高度
                 * 只有课程模式间隔才生效
                 */
                params.topMargin = (n - 1) * scheduleConfig.everyLessonHeight() + n * scheduleConfig.heightDistant()


                //按钮添加到时间栏布局中
                scheduleLayouts[0]!!.addView(timeButton, params)
            }
        } else{ //时间模式日期栏
            for (n in 0..23){
                val timeButton = Button(context)
                timeButton.apply {
                    //背景为透明
                    setBackgroundColor(Color.TRANSPARENT)

                    text = "$n:00"

                    //时间模式默认为从上居中开始，稍后考虑自定义
                    gravity = Gravity.CENTER_HORIZONTAL

                    //文字主要是设置上对齐，否则会有距离
                    setPadding(0, 0, 0, 0)
                }

                //高度需要计算
                val params = ConstraintLayout.LayoutParams(
                    ConstraintLayout.LayoutParams.MATCH_PARENT,
                    calculateLessonHeight(mode = scheduleConfig.scheduleDisplayMode())
                )

                //固定不动为0
                params.topToTop = 0
                params.leftToLeft = 0

                /**
                 * 主要对应从“几点”显示
                 * 第n点开始的数值：n * 一节高度
                 * 只有时间模式间隔才生效
                 */
                params.topMargin = n * scheduleConfig.everyLessonHeight()


                //按钮添加到时间栏布局中
                scheduleLayouts[0]!!.addView(timeButton, params)
            }
        }
    }

    //添加日程到布局
    private fun addSchedule() {
        if (courseList == null) return
        else {
            courseList!!.get().forEach {courseBean ->
                //如果当天时间显示
                if (scheduleConfig.showDayOfWeek()[courseBean.dayOfWeek - 1]){
                    //先判断是否显示非本周，如果显示然后再添加非非本周的，这样非本周在下面不会遮挡本周日程
                    if (scheduleConfig.showNotInThisWeek() && !courseBean.weeks.contains(thisWeek)){
                        addButton(courseBean, thisWeek = false)
                    }
                }
            }
            courseList!!.get().forEach {courseBean ->
                if (scheduleConfig.showDayOfWeek()[courseBean.dayOfWeek - 1]){
                    //再添加本周课程
                    if (courseBean.weeks.contains(thisWeek)) addButton(courseBean)
                }
            }
        }
    }

    /**
     * 添加日程格子
     */
    private fun addButton(courseBean: CourseBean, thisWeek: Boolean = true) {
        val button = Button(context)

        //按钮上的文字
        val buttonStringBuilder = StringBuilder()

        //按钮背景样式
        val backgroundDrawable = GradientDrawable().apply {
            cornerRadius = scheduleConfig.buttonCornerRadius()
            alpha = scheduleConfig.buttonAlpha()
            //背景颜色默认为灰色
            setColor(Color.GRAY)
        }

        //非本周字样
        if (!thisWeek) buttonStringBuilder.append("[非本周]")
        buttonStringBuilder.append(courseBean.lessonName)
        //本周才添加这些说明
        if (thisWeek) {
            buttonStringBuilder.append("\n@${courseBean.location}")
            if (scheduleConfig.showTeacher()) buttonStringBuilder.append("\n${courseBean.teacher}")

            //对于本周课程设置背景颜色
            backgroundDrawable.setColor(colorUtils.getColor(courseBean.lessonName))
        }
        button.text = buttonStringBuilder.toString()

        //按钮的一些配置
        button.apply {
            //关闭全部大写
            isAllCaps = false
            //文字布局
            gravity = if (scheduleConfig.buttonTextLocation() == ScheduleConfig.BUTTON_TEXT_START) Gravity.START else Gravity.CENTER
            //文字边距
            setPadding(scheduleConfig.buttonTextPadding(), scheduleConfig.buttonTextPadding(), scheduleConfig.buttonTextPadding(), scheduleConfig.buttonTextPadding())
            //文字大小
            textSize = scheduleConfig.buttonTextSize()
            //文字颜色
            setTextColor(Color.parseColor(scheduleConfig.buttonTextColor()))
            //背景样式
            background = backgroundDrawable
        }

        //高度需要计算
        val params = ConstraintLayout.LayoutParams(
            ConstraintLayout.LayoutParams.MATCH_PARENT,
            calculateLessonHeight(courseBean, scheduleConfig.scheduleDisplayMode())
        )

        //固定不动为0
        params.topToTop = 0
        params.leftToLeft = 0

        /**
         * 主要对应从“第几节”或者“哪个时间”显示
         * 第n节开始的数值：(n-1) * 一节高度 + n * 每节间隔高度
         * 只有课程模式间隔才生效
         */
        params.topMargin =
            if (scheduleConfig.scheduleDisplayMode() == ScheduleConfig.LESSON_MODE){
                //对于显示午休晚休情况，课程相应下串
                var start = courseBean.start

                //判断是否显示午休
                if (scheduleConfig.showRest()) {
                    if (start > scheduleConfig.noonRest()) start++
                    if (start > scheduleConfig.nightRest()) start++
                }

                (start - 1) * scheduleConfig.everyLessonHeight() + start * scheduleConfig.heightDistant()

            }
            else
                ((courseBean.startTime / 60.0) * scheduleConfig.everyLessonHeight()).toInt()
        //左间隔
        params.leftMargin= scheduleConfig.widthDistant()
        //右间隔
        params.rightMargin = scheduleConfig.widthDistant()

        //添加到当天布局
        scheduleLayouts[courseBean.dayOfWeek]?.addView(button, params)
    }

    /**
     * 计算格子的高度
     */
    private fun calculateLessonHeight(courseBean: CourseBean? = null, mode: Int): Int{
        if (courseBean == null) return scheduleConfig.everyLessonHeight()
        return if (mode == ScheduleConfig.LESSON_MODE)
                    scheduleConfig.everyLessonHeight() * (courseBean.end - courseBean.start + 1) + scheduleConfig.heightDistant() * (courseBean.end - courseBean.start)
               else //日程模式下，这两个差值为分钟，这里要以1个小时为一个单位高度。所以要除60
                    (scheduleConfig.everyLessonHeight() * (courseBean.endTime - courseBean.startTime) / (60.0)).toInt()
    }
}